package ru.spbau.goncharova.chat.client.serverMessages;

import ru.spbau.goncharova.chat.client.Client;
import ru.spbau.goncharova.chat.client.Message;
import ru.spbau.goncharova.chat.protocol.ProtocolHeader;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public abstract class ServerMessage implements Message {

    private ProtocolHeader header;
    protected ByteBuffer messageBuffer;

    public ServerMessage(ProtocolHeader header, ByteBuffer messageBuffer) {
        this.header = header;
        this.messageBuffer = messageBuffer;
    }

    @Override
    public ProtocolHeader getHeader() {
        return header;
    }

    @Override
    public byte[] getData() {
        return messageBuffer.array();
    }

    public void visit(Client client) {
        client.accept(this);
    }

    public static ServerMessage acceptMessage(SocketChannel channel) throws IOException {
        ByteBuffer headerBuffer = ByteBuffer.allocate(ProtocolHeader.getSize()).order(ProtocolHeader.order);
        channel.read(headerBuffer);
        ProtocolHeader header = ProtocolHeader.extractHeader(headerBuffer);
        if (header.getVersion() > Client.VERSION) {
            throw new RuntimeException("Incompatible versions: server version: " + header.getVersion() + " ru.spbau.goncharova.chat.client version: " + Client.VERSION);
        }
        ByteBuffer messageBuffer = ByteBuffer.allocate(header.getLength()).order(ProtocolHeader.order);
        channel.read(messageBuffer);
        ServerMessage result;
        switch (header.getMessageType()) {
            case FETCH_REPLY:
                result = new FetchReplyMessage(header, messageBuffer);
                break;
            case LOGIN_REPLY:
                result = new LoginReplyMessage(header, messageBuffer);
                break;
            case LOGOUT_REPLY:
                result = new LogoutReplyMessage(header, messageBuffer);
                break;
            case SEND_REPLY:
                result = new SendReplyMessage(header, messageBuffer);
                break;
            default: throw new IllegalArgumentException("Unexpected server message type: " + header.getMessageType());
        }
        return result;
    }

}
